package com.jsn.android.audio2

import android.annotation.SuppressLint
import android.media.MediaCodec
import android.media.MediaExtractor
import android.media.MediaFormat
import android.media.MediaFormat.KEY_MIME
import android.media.MediaMuxer
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.observe
import com.jsn.android.audio2.databinding.ActivityMp4Binding
import com.jsn.android.audio2.db.Mp4
import com.jsn.baselibx.ui.BaseActivity
import kotlinx.android.synthetic.main.activity_mp4.*
import kotlinx.android.synthetic.main.activity_wav.*
import kotlinx.coroutines.*
import java.io.File
import java.io.FileOutputStream
import java.nio.ByteBuffer
import java.util.concurrent.atomic.AtomicReference

@Suppress("BlockingMethodInNonBlockingContext")
class Mp4Activity : BaseActivity<ActivityMp4Binding>() {
    //                                                    -----> an error occurs in the job(job finished,flow ended)
    //                                                   |
    // (button clicked)                                  |
    //start mediaExtractor and MediaMuxer( flow started ) ----> finished with no exception(flow ended) ,we get a new mp4 file successfully


    // when a flow start we just let the button not enandled until a next flow starts
    val inFlow = MutableLiveData<Boolean>().apply { value = false } //flow not started util we click the button

    override fun getContentView(): Int {
        return R.layout.activity_mp4
    }

    @SuppressLint("SetTextI18n")
    @RequiresApi(Build.VERSION_CODES.O)
    override fun initUI() {

        inFlow.observe(this) {
            bt_extract.isEnabled = !(inFlow.value!!)
            bt_extract.text = if (inFlow.value!!) "converting" else "start"
        }

        progress.observe(this) { progress ->
            if (inFlow.value!!) { //if the mediaMuxer is working then we can see progress
                bt_extract.text = "${progress.first} of ${progress.second} done"
                tv_status.text =
                    ((progress.first / progress.second.toFloat()) * 100).toString().substring(0, 4) + "%" + " has been done"

            } else {
                tv_status.text = "not working"
            }
            bt_stop.isEnabled=inFlow.value!!
        }

        bt_extract.setSafeListener {
            extract()
        }

        bt_stop.setSafeListener {
            currentJob?.cancel()
        }
    }

    val job = SupervisorJob()

    val scope = CoroutineScope(Dispatchers.IO + job)

    val fileName = "666.mp4"

    var outPutStream: FileOutputStream? = null

    var mediaMuxer: MediaMuxer? = null

    var mediaExtractor: MediaExtractor? = null

    var lengthToatal = 0

    var read = 0

    var file: File? = null

    var currentJob:Job?=null

    var progress = MutableLiveData<Pair<Int, Int>>() //first :data has been read ; second:total data

    @RequiresApi(Build.VERSION_CODES.O)
    private fun extract() {
        //you followed the practice of strctured concurrency ,neat ,clever you are
        inFlow.value = true

        scope.launch {
            aoligeiaaa()
            //do other work will
        }

    }

    override fun initData() {
        lifecycleScope.launch {

        }
    }

    @RequiresApi(Build.VERSION_CODES.O)
    suspend fun aoligeiaaa(){
        coroutineScope {
            val launch: Job = launch {
                aoligei()
            }.also { currentJob=it }
        }
    }

    @RequiresApi(Build.VERSION_CODES.O)
    suspend fun aoligei(){
        try {
            lengthToatal = 0
            var trackIndex = -1
            var frameRate = 0
            val assetFileDescriptor =
                assets.openFd(fileName).also { lengthToatal = it.length.toInt() }
            val mediaExtractor = MediaExtractor().apply {
                setDataSource(assetFileDescriptor)
            }.also { mediaExtractor = it }
            for (i in 0 until mediaExtractor.trackCount) {
                val index = i
                val trackFormat = mediaExtractor.getTrackFormat(index)
                val mime = trackFormat.getString(KEY_MIME)
                if (!mime.startsWith("video/")) continue
                frameRate = trackFormat.getInteger(MediaFormat.KEY_FRAME_RATE)
                mediaExtractor.selectTrack(i)
                val create = File(cacheDir, "${System.currentTimeMillis()}.mp4").apply {
                    if (!exists()) createNewFile()
                    outPutStream = FileOutputStream(this)
                    file = this
                }
                mediaMuxer =
                    MediaMuxer(outPutStream!!.fd, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
                trackIndex = mediaMuxer!!.addTrack(trackFormat)
                mediaMuxer?.start()
            }
            if (mediaMuxer == null) {
                inFlow.postValue(false)
                return
            }
            val info = MediaCodec.BufferInfo()
            info.presentationTimeUs = 0
            val buffer = ByteBuffer.allocate(500 * 1024)
            while (true) {
                val readBytes = mediaExtractor.readSampleData(buffer, 0)
                if (readBytes < 0) break
                mediaExtractor.advance()
                info.offset = 0
                info.size = readBytes
                info.flags = MediaCodec.BUFFER_FLAG_KEY_FRAME
                info.presentationTimeUs += 1000 * 1000 / frameRate
                mediaMuxer!!.writeSampleData(trackIndex, buffer, info)
                read += readBytes
                progress.postValue(read to lengthToatal)
                //pretend to be slow so we can see progress clearly
                delay(50)
            }
        } finally {
            runOnUiThread { toast(file?.name?:  "file nor exist") }
            read = 0
            lengthToatal = 0
            mediaExtractor?.release()
            mediaMuxer?.stop()
            mediaExtractor?.release()
            inFlow.postValue(false)
            progress.postValue(100 to 100) //post to show "not working"
            yield()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        job.cancel()
    }



    suspend fun playGround():String=
         coroutineScope {
            val task: Deferred<String> = async {
                delay(50) //simulate loading for 0.05 second
                " " }
             val launch: Job = launch {
                 //do nothing
                 delay(1000)
             }
             //yield()
            return@coroutineScope task.await()
        }

}

/*

    fun coroutine(){
        scope.launch {
            gaga()
            //code block
        }
    }
*/

    /*suspend fun gaga(){
        val coroutineScope: Job = coroutineScope {
            //create a child scope which is child of caller Scope
            launch {
                //子线程中执行
                //task1
                //do1
                //do2
                //do3
                launch {
                    //create another child scope
                    //fire and let go
                    val get: String = get()
                }

            }

            launch {
                //task2
            }
        }
        coroutineScope{

        }
    }


    suspend fun get()= withContext(Dispatchers.IO){
      String()
    }*/

